# This program is licensed under the GNU GPL v2 (see [COPYING]) and
# [http://www.python.org/download/releases/2.4.2/license/ Python Licenses]

# Copyright Thomas Johler (c) 2007

import os, dictdlib

class DictDB(dictdlib.DictDB):

  def __init__(self, basename, mode = 'read', quiet = 0, ignorecompiled=False):
    self.ignorecompiled = ignorecompiled
    self.iscompiled     = False
    self.basename       = basename
    self.mode           = mode

    dictdlib.DictDB.__init__(self, basename, mode=mode, quiet=quiet)

  def _initindex(self):
    # reopen the index with line buffering in binary mode
    self.indexfile.close()
    self.indexfile = file(self.indexfilename, "rb", 1)
    
    if not os.path.isfile(self.basename+".cindex") or self.ignorecompiled:
      self.indexlines = []
      pos = 0
      line = self.indexfile.readline() # use readline to avoid buffering
      while line != '':
        self.indexlines += [ pos ]
        pos = self.indexfile.tell()
        del line
        line = self.indexfile.readline()
    else:
      import marshal, gzip
      cidx = gzip.GzipFile(self.basename+".cindex", "rb")
      buf  = cidx.read()
      self.indexlines = marshal.loads(buf)
      del buf
      cidx.close()
      self.iscompiled = True

    self.numEntries = len(self.indexlines)

  def compileIndex(self, overwrite=True):
    if os.path.isfile(self.basename+".cindex") and not overwrite:
      return
    import marshal, gzip
    cidx = file(self.basename+".cindex", "wb")
    gz   = gzip.GzipFile(os.path.basename(self.basename)+".marshal", "wb", fileobj=cidx)
    buf  = marshal.dumps(self.indexlines)
    gz.write(buf)
    del buf
    gz.close()
    cidx.close()
    self.iscompiled = True
    
  def close(self):
    self.indexfile.close()
    self.dictfile.close()

  def deleteCompiled(self):
    if os.path.isfile(self.basename+".cindex"):
      os.remove(self.basename+".cindex")
      
  def hasdef(self, word):
    if self.indexentries.has_key(word):
      return True
    start, len, line = self.findIndex(word)
    if start != None:
      self.indexentries[word] = [ [start, len] ]
      return True
    return False
  
  def __index(self, lineno):
    self.indexfile.seek(self.indexlines[lineno])
    w, s, l = self.indexfile.readline().strip('\n').strip('\r').split('\t')
    return w, dictdlib.b64_decode(s), dictdlib.b64_decode(l)
    
  def findIndex(self, word, pos = 0, end = -1):
    if end == -1: end = len(self.indexlines) - 1
    sect = pos + (end - pos) / 2
    c, s, l = self.__index(sect)
    c = c.decode("utf-8").lower()
    w = word.decode("utf-8").lower()
    if w == c:       return s, l, sect
    if end-pos < 1:  return None, None, sect
    if end-pos == 1: return self.findIndex(word, end,    end)
    if w > c:        return self.findIndex(word, sect+1, end)
    else:            return self.findIndex(word, pos,    sect-1)


  def nearest(self, word):
    _start, _len, pos = self.findIndex(word)
    return pos
    
  def indexdef(self, lineno):
    word, start, len = self.__index(lineno)
    self.dictfile.seek(start)
    return word, self.dictfile.read(len)
    # return "%03d: %s" % (lineno, word), self.dictfile.read(len)
